﻿using BCCommon;
using BCCommon.Enums;
using BCCommon.ExceptionExtensions;
using BCCommon.Extensions;
using BCDto.UploadHandleComponent;
using BCService.Common.OSS;
using BCService.Common.UploadFileRecord;
using BCService.UploadHandleComponent;
using BCTMSRESTful.Configs;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace BCTMSRESTful.Controllers
{
    /// <summary>
    /// 上传控制器
    /// </summary>
    [Route("api/v1/[controller]")]
    public class UploadController : BCTMSRESTfulAPIController
    {
        private readonly IConfiguration configuration;
        private readonly IUploadFileInfoHandleService uploadFileInfoHandleService;
        private readonly IUploadHandleService uploadHandleService;
        private readonly IUploadFileRecordService uploadFileRecordService;
        private readonly IOSSObject ossObject;

        public UploadController(IConfiguration configuration,
            IUploadFileInfoHandleService uploadFileInfoHandleService,
            IUploadHandleService uploadHandleService,
            IUploadFileRecordService uploadFileRecordService,
            IOSSObject ossObject)
        {
            this.configuration = configuration;
            this.uploadFileInfoHandleService = uploadFileInfoHandleService;
            this.uploadHandleService = uploadHandleService;
            this.uploadFileRecordService = uploadFileRecordService;
            this.ossObject = ossObject;
        }

        /// <summary>
        /// RemarkType解释说明
        /// </summary>
        /// <returns>返回RemarkType的枚举解释说明</returns>
        [HttpGet]
        [ProducesResponseType(typeof(List<string>), 200)]
        public IActionResult Get()
        {
            List<string> list = new List<string>();
            foreach (object o in Enum.GetValues(typeof(UploadFileRemarkType)))
            {
                UploadFileRemarkType remarkType = ((UploadFileRemarkType)(int)o);
                list.Add(string.Format("{0}:{1}  {2}", o, Enum.Format(typeof(UploadFileRemarkType), o, "D"), remarkType.GetDescriptionString()));
            }
            //list.Add("如果存在RemarkJSON字段，则必须是JSON格式");
            return this.Ok(list);
        }

        /// <summary>
        /// 上传图片。
        /// </summary>
        /// <param name="from">上传文件信息</param>
        /// <response code="200">上传地址。</response>
        /// <response code="401">请求需要认证或者认证信息已过期。</response>
        /// <response code="403">无权访问指定的功能。</response>
        /// <returns></returns>
        [HttpPost]
        [ProducesResponseType(typeof(UploadResponseDto), 200)]
        public IActionResult Upload(IFormCollection from)
        {
            var data = from.Files["data"];
            UploadFileDto uploadFileDto = uploadFileInfoHandleService.Init(from["fileName"], from["usage"],".jpg");

            //if (!Directory.Exists(uploadFileDto.DirectoryPath))
            //{
            //    Directory.CreateDirectory(uploadFileDto.DirectoryPath);
            //}

            if (data == null || data.Length <= 0)
            {
                return BadRequest("文件错误！");
            }
            if (from.Any(p => p.Key.Equals("remark")))
            {
                if (Enum.TryParse(typeof(UploadFileRemarkType), from["remark"], out object value))
                {
                    uploadFileDto.RemarkType = (UploadFileRemarkType)value;
                    if (from.Any(p => p.Key.Equals("remarkJSON")))
                    {
                        uploadFileDto.Remarks = JsonConvert.DeserializeObject<Dictionary<string, object>>(from["remarkJSON"]);
                    }
                }
                else
                {
                    throw new ArgumentException("备注服务类型不正确。");
                }
            }
            uploadFileInfoHandleService.ChangeFolderName(uploadFileDto);
            uploadFileDto.ContentLength = data.Length;
            uploadHandleService.CheckData(uploadFileDto);
            using (FileStream fs = new FileStream(uploadFileDto.FilePath, FileMode.Create))
            {
                data.CopyTo(fs);
                Stream sm = data.OpenReadStream();
                var br = new BinaryReader(sm);
                if (uploadFileDto.FolderName == "image")
                {
                    CheckFileSecurity(br);
                }
                byte[] bytes = br.ReadBytes((int)sm.Length);
                uploadFileDto.Content = bytes;
                fs.Flush();
            }
            UploadResponseDto uploadResponseDto = uploadHandleService.UploadHandle(uploadFileDto);
            uploadResponseDto.Src = uploadFileDto.Src;
            uploadResponseDto.Host = configuration["CurrentlyImageHost"];
            if (uploadResponseDto.Src.IndexOf("/") == 0&& uploadResponseDto.Host.Substring(0, uploadResponseDto.Host.Length-1)=="/")
            {
                uploadResponseDto.Host = uploadResponseDto.Host.TrimEnd('/');
            }
#if !DEBUG
            #region OSS对接
            string bucketName = configuration["AliyunOSSAPI:Buckets:0:name"];
            string localFileName = Path.Combine(uploadFileDto.DirectoryPath, uploadFileDto.FileName + uploadFileDto.FileSuffix);
            string smallLocalFileName = Path.Combine(uploadFileDto.DirectoryPath, uploadFileDto.FileName + "_50x50" + uploadFileDto.FileSuffix);
            string objectName = uploadFileDto.Src;
            string smallObjectName = uploadFileDto.Src.Replace(uploadFileDto.FileName, uploadFileDto.FileName + "_50x50" + uploadFileDto.FileSuffix);
            if (!ossObject.DoesObjectExist(bucketName, objectName))
            {
                if (!ossObject.PutObjectCallback(bucketName, objectName, localFileName, uploadFileDto.FileName, out bool fileExists))
                {
                    uploadFileRecordService.Delete(uploadFileDto.FileName);
                    throw new ArgumentException("原图上传失败");
                }

                if (!fileExists)
                {
                    uploadFileRecordService.Delete(uploadFileDto.FileName);
                }

                if (!ossObject.PutObjectCallback(bucketName, smallObjectName, smallLocalFileName, uploadFileDto.FileName, out bool smallFileExists))
                {
                    uploadFileRecordService.Delete(uploadFileDto.FileName);
                    throw new ArgumentException("缩略图上传失败");
                }
            }
            #endregion
#endif

            return Ok(uploadResponseDto);
        }
        /// <summary>
        /// 文件安全检查
        /// </summary>
        /// <param name="br">二进制字节流</param>
        private void CheckFileSecurity(BinaryReader br)
        {
            string fileClass;
            byte buffer;
            byte[] b = new byte[2];
            buffer = br.ReadByte();
            b[0] = buffer;
            fileClass = buffer.ToString();
            buffer = br.ReadByte();
            b[1] = buffer;
            fileClass += buffer.ToString();
            Dictionary<string, string> securityCode = new Dictionary<string, string>();
            //7790是Exe,8297是rar
            securityCode.Add("255216", "jpg");
            securityCode.Add("7173", "gif");
            securityCode.Add("6677", "BMP");
            securityCode.Add("13780", "PNG");
            if (!securityCode.Any(p => p.Key.Equals(fileClass)))
            {
                throw new UploadFileException("此文件不允许上传。");
            }
        }

        private void Log(IFormCollection from)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(Directory.GetCurrentDirectory());
            string path = Path.Combine(directoryInfo.FullName, "uploadRecord", DateTime.Now.ToString("yyyy-MM-dd"));
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            FileInfo fileInfo = new FileInfo(Path.Combine(path, "uploadRecord.txt").ToString());

            if (!fileInfo.Exists)
            {
                using (StreamWriter sw = fileInfo.CreateText())
                {
                    sw.WriteLine("*****************************************");
                    sw.WriteLine("当前时间：{0}", DateTime.Now.ToString());
                    foreach (var item in from)
                    {
                        sw.WriteLine("{0}:{1}", item.Key, item.Value);
                    }

                }
            }
            else
            {
                using (StreamWriter sw = fileInfo.AppendText())
                {
                    sw.WriteLine("*****************************************");
                    sw.WriteLine("当前时间：{0}", DateTime.Now.ToString());
                    foreach (var item in from)
                    {
                        sw.WriteLine("{0}:{1}", item.Key, item.Value);
                    }
                }
            }
        }
    }
}
